package adc.app.ui.wicket.model;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;

import adc.app.spec.IBo;
import adc.app.spec.IBoBs;

public class DomainObjectListModel<T extends IBo> 
	extends LoadableDetachableModel<List<T>> {

	private static final long serialVersionUID = 1L;

	private final IModel<? extends IBoBs<T>> serviceModel;
	
	private final Map<String, IModel<?>> filterByProperties;
	private final String sortExpression;
	private final Boolean sortAscending;
	private final Integer firstIndex;
	private final Integer maxSize;
	
	public <S extends IBoBs<T>> DomainObjectListModel(
			Class<S> serviceClass,
			Map<String, IModel<?>> filterByProperties,
			String sortExpression, Boolean sortAscending, Integer firstIndex,
			Integer maxSize) {
		super();
		this.serviceModel = new SpringBeanModel<S>(serviceClass);
		this.filterByProperties = filterByProperties != null ? 
				new HashMap<String, IModel<?>>(filterByProperties) : null;
		this.sortExpression = sortExpression;
		this.sortAscending = sortAscending;
		this.firstIndex = firstIndex;
		this.maxSize = maxSize;
	}
	
	public <S extends IBoBs<T>> DomainObjectListModel(
			Class<S> serviceClass,
			Map<String, IModel<?>> filterByProperties,
			String sortExpression, Boolean sortAscending) {
		this(serviceClass, filterByProperties, sortExpression, sortAscending, null, null);
	}
	
	public <S extends IBoBs<T>> DomainObjectListModel(
			Class<S> serviceClass,
			String sortExpression, Boolean sortAscending) {
		this(serviceClass, null, sortExpression, sortAscending);
	}
	
	public <S extends IBoBs<T>> DomainObjectListModel(
			Class<S> serviceClass) {
		this(serviceClass, null, null);
	}

	@Override
	protected List<T> load() {
		Map<String, Object> filter = null;
		if (filterByProperties != null) {
			filter = new HashMap<String, Object> (filterByProperties.size());
			for (Entry<String, IModel<?>> entry : filterByProperties.entrySet()) {
				filter.put(entry.getKey(), entry.getValue().getObject());
			}
		}
		IBoBs<T> service = serviceModel.getObject();
		Map<String, Boolean> sort = null;
		if (sortExpression != null) {
		    sort = Collections.singletonMap(sortExpression, Boolean.TRUE.equals(sortAscending));
		}
		return service.list(filter, firstIndex, maxSize, sort);
	}

	@Override
	protected void onDetach() {
		serviceModel.detach();
		if (filterByProperties != null) {
			for (IModel<?> propValueModel : filterByProperties.values()) {
				propValueModel.detach();
			}
		}
	}
	
	
}
